
from fuse import FUSE, Operations
from time import time
from stat import *
from errno import ENOENT
from collections import defaultdict
import MySQLdb
import os, sys

NODE_NAME = "sandra"

MeFS_DB_HOST = "localhost"
MeFS_DB_USER = "root"
MeFS_DB_PASS = ""
MeFS_DB_DATABASE = "mediafs"

MeFS_NAME_AUDIO = "Audio"
MeFS_NAME_VIDEO = "Video"
MeFS_NAME_PHOTO = "Photos"

MeFS_NAME_ARTISTS = "Artists"
MeFS_NAME_ALBUMS = "Albums"
MeFS_NAME_TITLES = "Titles"
MeFS_NAME_GENRES = "Genres"

MeFS_DIR_MODE = dict (st_mode=(S_IFDIR | 0777), st_ctime=0, st_time=0, st_atime=0, st_link=2)
MeFS_FILE_MODE = dict (st_mode=(S_IFREG | 0444), st_ctime=0, st_time=0, st_atime=0, st_link=1)

class MediaFS (Operations):

    def title_from_file (self, filename):
	p = filename.rfind(".")
	return filename[0:p]

    def __init__(self, debug=True):
	self.fh = dict()
	self.debug = debug
	self.db = MySQLdb.connect (host = MeFS_DB_HOST, user = MeFS_DB_USER, passwd = MeFS_DB_PASS, db = MeFS_DB_DATABASE);

    # implement opendir

    def readdir(self, path, fh):
	p = path.split("/")
	# root
	if (path == "/"):
	    return [".","..",MeFS_NAME_AUDIO, MeFS_NAME_VIDEO, MeFS_NAME_PHOTO];
	# Audio, Video, Photos
	elif (len(p)==2):
	    if (p[1] == MeFS_NAME_AUDIO):
		return [".","..",MeFS_NAME_ARTISTS, MeFS_NAME_ALBUMS, MeFS_NAME_TITLES, MeFS_NAME_GENRES];
	    else:
		 return -ENOENT
	elif (len(p)==3):
	    # Songs -> Titles
	    if (p[1] == MeFS_NAME_AUDIO and p[2] == MeFS_NAME_TITLES):
		list = [".",".."];
		cursor = self.db.cursor(MySQLdb.cursors.DictCursor)
		cursor.execute ("SELECT title_name FROM titles");
		rows = cursor.fetchall ()
		for row in rows:
		    list.append (row["title_name"])
		cursor.close ()
		return list
	    # Songs -> Artists
	    if (p[1] == MeFS_NAME_AUDIO and p[2] == MeFS_NAME_ARTISTS):
		list = [".",".."];
		cursor = self.db.cursor(MySQLdb.cursors.DictCursor)
		cursor.execute ("SELECT artist_name FROM artists");
		rows = cursor.fetchall ()
		for row in rows:
		    # check length to be != 0 or "   "
		    list.append (row["artist_name"])
		cursor.close ()
		return list
	    else:
		return -ENOENT
	elif (len(p)==4):
	    # Songs -> Titles -> title
	    if (p[1] == MeFS_NAME_AUDIO and p[2] == MeFS_NAME_TITLES):
		list = [".",".."];
		cursor = self.db.cursor(MySQLdb.cursors.DictCursor)
		cursor.execute ("SELECT title_name FROM titles");
		rows = cursor.fetchall ()
		for row in rows:
		    list.append (row["title_name"])
		cursor.close ()
		return list
	    # Songs -> Artists -> artist
	    if (p[1] == MeFS_NAME_AUDIO and p[2] == MeFS_NAME_ARTISTS):
		list = [".",".."];
		cursor = self.db.cursor(MySQLdb.cursors.DictCursor)
		# get artist id
		cursor.execute ("SELECT artist_id FROM artists WHERE artist_name LIKE %s", (p[3]));
		row = cursor.fetchone ()
		artist_id = row["artist_id"]
		if (artist_id!=0):
		    cursor.execute ("SELECT song_id, title_name, filetype_name FROM songs INNER JOIN artists ON song_artist = artist_id INNER JOIN files ON song_file = file_id INNER JOIN filetypes ON file_type = filetype_id INNER JOIN titles ON song_title = title_id WHERE song_artist = %s", artist_id);
		    rows = cursor.fetchall ()
		    for row in rows:
			# check length to be != 0 or "   "
			list.append (row["title_name"]+"."+row["filetype_name"])
			list.append ("."+row["title_name"])
		    return list
		else:
		    return -ENOENT
		cursor.close ()
	    else:
		return -ENOENT
	elif (len(p)==5):
	    # Songs -> Artists -> artist -> .title
	    if (p[1] == MeFS_NAME_AUDIO and p[2] == MeFS_NAME_ARTISTS):
		# should be better tested, so that the title really exists
		list = [".","..", "title.txt", "artist.txt", "album.txt", "genre.txt", "year.txt", "track.txt", "comment.txt"];
		return list
	    else:
		return -ENOENT
	else:
	    return  -ENOENT

    def getattr(self, path, fh=None):
	# root
	p = path.split("/")
	if (path == "/"):
	    return MeFS_DIR_MODE
	# Audio, Video, Photos
	elif (len(p)==2):
	    # Songs
	    if (p[1] == MeFS_NAME_AUDIO or p[1] == MeFS_NAME_VIDEO or p[1] == MeFS_NAME_PHOTO):
		return MeFS_DIR_MODE
	    else:
		return -ENOENT
	elif (len(p)==3):
	    # Songs
	    if (p[1] == MeFS_NAME_AUDIO and (p[2] == MeFS_NAME_ALBUMS or p[2] == MeFS_NAME_ARTISTS or p[2] == MeFS_NAME_TITLES or p[2] == MeFS_NAME_GENRES)):
		return MeFS_DIR_MODE
	    else:
		return -ENOENT
	elif (len(p)==4):
	    # Songs -> Titles -> title
	    if (p[1] == MeFS_NAME_AUDIO and p[2] == MeFS_NAME_TITLES):
		# check in database required, faster if the check is not performed
		return MeFS_DIR_MODE
	    # Songs -> Artists -> artist
	    if (p[1] == MeFS_NAME_AUDIO and p[2] == MeFS_NAME_ARTISTS):
		# check in database required, faster if the check is not performed
		return MeFS_DIR_MODE
	    else:
		return -ENOENT
	elif (len(p)==5):
	    # Songs -> Titles
	    if (p[1] == MeFS_NAME_AUDIO and p[2] == MeFS_NAME_TITLES):
		# check in database required, faster if the check is not performed
		if (p[4] == "." or p[4] == ".."):
		    return MeFS_DIR_MODE
		else:
		    return MeFS_FILE_MODE
	    # Songs -> Artists -> artist -> song
	    if (p[1] == MeFS_NAME_AUDIO and p[2] == MeFS_NAME_ARTISTS):
		if (p[4] == "." or p[4] == ".."):
		    return MeFS_DIR_MODE
		else:
		    if (p[4][0]!='.'):
			cursor = self.db.cursor(MySQLdb.cursors.DictCursor)
			# get artist id
			cursor.execute ("SELECT artist_id FROM artists WHERE artist_name LIKE %s", (p[3]));
			row = cursor.fetchone ()
			artist_id = row["artist_id"]
			if (artist_id!=0):
			    cursor.execute ("SELECT file_path, file_name, file_size, file_modify_time FROM songs INNER JOIN artists ON song_artist = artist_id INNER JOIN files ON song_file = file_id INNER JOIN titles ON song_title = title_id WHERE song_artist = %s AND title_name LIKE %s", (artist_id, self.title_from_file(p[4])));
			    row = cursor.fetchone ()
			    mode = os.stat (row["file_path"]+"/"+row["file_name"])
			    return dict (st_mode=S_IFREG | 0444, st_ctime=mode.st_ctime, st_time=mode.st_mtime, st_atime=mode.st_atime, st_link=1, st_size = mode.st_size)
			else:
			    return -ENOENT
		    else:
			return MeFS_DIR_MODE
	    else:
		return -ENOENT
	elif (len(p)==6):
	    # Songs -> Artists -> artist -> .song -> info.txt
	    if (p[1] == MeFS_NAME_AUDIO and p[2] == MeFS_NAME_ARTISTS):
		if (p[5] == "." or p[5] == ".."):
		    return MeFS_DIR_MODE
		else:
		    if (p[5][0]!='.'):
			if (p[5] == "artist.txt"):
			    return dict (st_mode=S_IFREG | 0444, st_ctime=0, st_time=0, st_atime=0, st_link=1, st_size = len(p[3]))
			elif (p[5] == "title.txt"):
			    return dict (st_mode=S_IFREG | 0444, st_ctime=0, st_time=0, st_atime=0, st_link=1, st_size = len(p[4][1:]))
			elif (p[5] == "album.txt"):
			    cursor = self.db.cursor(MySQLdb.cursors.DictCursor)
			    # get artist id
			    cursor.execute ("SELECT artist_id FROM artists WHERE artist_name LIKE %s", (p[3]));
			    row = cursor.fetchone ()
			    artist_id = row["artist_id"]
			    if (artist_id!=0):
				cursor.execute ("SELECT album_name FROM songs INNER JOIN albums ON song_album = album_id INNER JOIN titles ON song_title = title_id WHERE song_artist = %s AND title_name LIKE %s", (artist_id, p[4][1:]));
				row = cursor.fetchone ()
				return dict (st_mode=S_IFREG | 0444, st_ctime=0, st_time=0, st_atime=0, st_link=1, st_size = len(row["album_name"]))
			    cursor.close ()
			elif (p[5] == "genre.txt"):
			    cursor = self.db.cursor(MySQLdb.cursors.DictCursor)
			    # get artist id
			    cursor.execute ("SELECT artist_id FROM artists WHERE artist_name LIKE %s", (p[3]));
			    row = cursor.fetchone ()
			    artist_id = row["artist_id"]
			    if (artist_id!=0):
				cursor.execute ("SELECT genre_name FROM songs INNER JOIN genres ON song_genre = genre_id INNER JOIN titles ON song_title = title_id WHERE song_artist = %s AND title_name LIKE %s", (artist_id, p[4][1:]));
				row = cursor.fetchone ()
				return dict (st_mode=S_IFREG | 0444, st_ctime=0, st_time=0, st_atime=0, st_link=1, st_size = len(row["genre_name"]))
			    cursor.close ()
			elif (p[5] == "year.txt"):
			    cursor = self.db.cursor(MySQLdb.cursors.DictCursor)
			    # get artist id
			    cursor.execute ("SELECT artist_id FROM artists WHERE artist_name LIKE %s", (p[3]));
			    row = cursor.fetchone ()
			    artist_id = row["artist_id"]
			    if (artist_id!=0):
				cursor.execute ("SELECT song_year FROM songs INNER JOIN titles ON song_title = title_id WHERE song_artist = %s AND title_name LIKE %s", (artist_id, p[4][1:]));
				row = cursor.fetchone ()
				return dict (st_mode=S_IFREG | 0444, st_ctime=0, st_time=0, st_atime=0, st_link=1, st_size = len(row["song_year"]))
			    cursor.close ()
			elif (p[5] == "track.txt"):
			    cursor = self.db.cursor(MySQLdb.cursors.DictCursor)
			    # get artist id
			    cursor.execute ("SELECT artist_id FROM artists WHERE artist_name LIKE %s", (p[3]));
			    row = cursor.fetchone ()
			    artist_id = row["artist_id"]
			    if (artist_id!=0):
				cursor.execute ("SELECT song_track FROM songs INNER JOIN titles ON song_title = title_id WHERE song_artist = %s AND title_name LIKE %s", (artist_id, p[4][1:]));
				row = cursor.fetchone ()
				return dict (st_mode=S_IFREG | 0444, st_ctime=0, st_time=0, st_atime=0, st_link=1, st_size = len(string(row["song_track"])))
			    cursor.close ()
			elif (p[5] == "comment.txt"):
			    cursor = self.db.cursor(MySQLdb.cursors.DictCursor)
			    # get artist id
			    cursor.execute ("SELECT artist_id FROM artists WHERE artist_name LIKE %s", (p[3]));
			    row = cursor.fetchone ()
			    artist_id = row["artist_id"]
			    if (artist_id!=0):
				cursor.execute ("SELECT song_comment FROM songs INNER JOIN titles ON song_title = title_id WHERE song_artist = %s AND title_name LIKE %s", (artist_id, p[4][1:]));
				row = cursor.fetchone ()
				return dict (st_mode=S_IFREG | 0444, st_ctime=0, st_time=0, st_atime=0, st_link=1, st_size = len(row["song_comment"]))
			    cursor.close ()
		    else:
			return MeFS_DIR_MODE
	return -ENOENT

    def open (self, path, flags):
	p = path.split ("/")
	if (len(p) == 5):
	    # Audio -> Artists -> artist -> title
	    if (p[1] == MeFS_NAME_AUDIO and p[2] == MeFS_NAME_ARTISTS):
		cursor = self.db.cursor(MySQLdb.cursors.DictCursor)
		# get artist id
		cursor.execute ("SELECT artist_id FROM artists WHERE artist_name LIKE %s", (p[3]));
		row = cursor.fetchone ()
		artist_id = row["artist_id"]
		if (artist_id!=0):
		    cursor.execute ("SELECT file_path, file_name, file_size, file_modify_time FROM songs INNER JOIN artists ON song_artist = artist_id INNER JOIN files ON song_file = file_id INNER JOIN titles ON song_title = title_id WHERE song_artist = %s AND title_name LIKE %s", (artist_id, self.title_from_file(p[4])));
		    row = cursor.fetchone ()
		    fh = os.open (row["file_path"]+"/"+row["file_name"], os.O_RDONLY)
		    if (fh>0):
			self.fh[path] = fh
		    return fh
	    else:
		return -ENOENT
	return -ENOENT

    def read (self, path, size, offset, fh):
	os.lseek (fh, offset, 0)
	return os.read (fh, size)
    
    def release (self, path, fh):
	self.fh.pop (path)
	return os.close (fh)

    def chmod(self, path, mode):
	return 0

if __name__ == "__main__":
    mediafs = FUSE(MediaFS(), "/tmp/MediaFS", foreground=True, nothreads=True)
